package com.cashmama.market.api.domain.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cashmama.market.api.domain.enums.Stage2ResultEnum;
import com.cashmama.market.api.domain.vo.risk.highmark.ReportStage1Dto;
import com.cashmama.market.api.domain.vo.risk.highmark.ReportStage2Dto;
import com.cashmama.market.api.domain.vo.risk.highmark.Stage1Request;
import com.cashmama.market.api.infras.config.ApolloConfigUtil;
import com.cashmama.market.api.infras.consts.RedisKeyConsts;
import com.cashmama.market.api.infras.exception.ApplicationException;
import com.cashmama.market.api.infras.utils.HttpUtil;
import com.fqgj.base.services.oss.OSSService;
import com.fqgj.base.services.redis.RedisClient;
import com.fqgj.common.utils.DateUtil;
import com.fqgj.xjd.user.client.UserHighmarkService;
import com.fqgj.xjd.user.client.enums.UserHighmarkStatusEnum;
import com.fqgj.xjd.user.client.enums.UserKycTypeEnum;
import com.fqgj.xjd.user.client.request.UserHighmarkVo;
import com.fqgj.xjd.user.client.response.UserAuthEmail;
import com.fqgj.xjd.user.client.response.UserInfo;
import com.fqgj.xjd.user.client.response.UserKycDocumentInfo;
import com.fqgj.xjd.user.client.response.UserPanInfo;
import com.qianli.cashmama.trade.common.utils.TextFormatUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @program: market-api
 * @description
 * @author: frank
 * @create: 2020-01-10 15:24
 **/
@Component
public class HighMarkReportService {
    private static final Logger LOGGER = LoggerFactory.getLogger(HighMarkReportService.class);

    private String[] stage1Url = {"https://test.crifhighmark.com/Inquiry/do.getSecureService/DTC/initiate",
            "https://cir.crifhighmark.com/Inquiry/do.getSecureService/DTC/initiate"};
    private String[] stage2Url = {"https://test.crifhighmark.com/Inquiry/do.getSecureService/DTC/response",
            "https://cir.crifhighmark.com/Inquiry/do.getSecureService/DTC/response"};
    private String[] stage3Url = {"https://test.crifhighmark.com/Inquiry/do.getSecureService/DTC/response",
            "https://cir.crifhighmark.com/Inquiry/do.getSecureService/DTC/response"};

    @Autowired
    private ApolloConfigUtil configUtil;

    @Autowired
    private RedisClient redisClient;

    @Autowired
    private UserHighmarkService userHighmarkService;

    @Autowired
    private OSSService ossService;

    /**
     * 模拟成功
     *
     * @param userCode
     */
    public void mockSuccess(String userCode) {
        LOGGER.info("用户highmark报告mock通过,userCode:{}", userCode);
        UserHighmarkVo userHighmarkVo = new UserHighmarkVo();
        userHighmarkVo.setUserCode(userCode)
                .setOrderId(UUID.randomUUID().toString().replaceAll("-", ""))
                .setReportId("")
                .setStage(1)
                .setStatus(UserHighmarkStatusEnum.SUCCESS_SKIP.getStatus());
        userHighmarkService.addUserHighmark(userHighmarkVo);
    }

    /**
     * No Hit 模拟成功
     *
     * @param userCode
     */
    public void noHitSuccess(String userCode) {
        LOGGER.info("用户highmark报告nohit通过,userCode:{}", userCode);
        UserHighmarkVo userHighmarkVo = new UserHighmarkVo();
        userHighmarkVo.setUserCode(userCode)
                .setOrderId(UUID.randomUUID().toString().replaceAll("-", ""))
                .setReportId("")
                .setStage(2)
                .setStatus(UserHighmarkStatusEnum.SUCCESS_NO_HIT.getStatus());
        userHighmarkService.addUserHighmark(userHighmarkVo);
    }

    /**
     * 第一步
     *
     * @param userCode
     * @return
     */
    public String stage1(String userCode, UserInfo userInfo, UserAuthEmail userAuthEmail, UserKycDocumentInfo userKycDocumentInfo, UserPanInfo userPanInfo) {
        String orderId = UUID.randomUUID().toString().replaceAll("-", "");
        LOGGER.info("HighMarkStage1,获取用户信息成功,userCode:{},orderId:{}", userCode, orderId);

        JSONObject highmarkConfig = configUtil.getHighmarkConfig();
//        String customerId = "DTC0000041";
//        String productCode = "BBC_CONSUMER_SCORE#85#2.0";
//        String userId = "chm_uat@cashmama.in";
//        String password = "E45768547AE4AD7E359C159968032C34ACED52C6";
//        String appID = "DO!*9A!*U1o%i&C&!&n&)it)";
//        String merchantID = "DTC0000041";

        String customerId = highmarkConfig.getString("customerId");
        String productCode = highmarkConfig.getString("productCode");
        String userId = highmarkConfig.getString("userId");
        String password = highmarkConfig.getString("password");
        String appID = highmarkConfig.getString("appID");
        String merchantID = highmarkConfig.getString("merchantID");

        Stage1Request stage1Request = new Stage1Request();

        stage1Request.setFirstName(null2empty(userInfo.getUserBase().getFirstName()));
        stage1Request.setMiddleName(null2empty(userInfo.getUserBase().getMiddleName()));
        stage1Request.setLastName(null2empty(userInfo.getUserBase().getLastName()));
        stage1Request.setGender(null2empty(""));
        stage1Request.setDob(null2empty(DateUtil.getDate(DateUtil.getDate(userInfo.getUserBase().getBirthday(), "yyyy-MM-dd"), "dd-MM-yyyy")));

        stage1Request.setAgeAsOnToday(null2empty(""));
        stage1Request.setMaritalStatus(null2empty(""));
        stage1Request.setMob1(null2empty(userInfo.getUser().getMobile()));
        stage1Request.setMob2(null2empty(""));
        stage1Request.setMob3(null2empty(""));

        stage1Request.setEmail1(null2empty(userAuthEmail.getEmail()));
        stage1Request.setEmail2(null2empty(""));
        stage1Request.setPan(null2empty(userPanInfo.getCardNo()));
        stage1Request.setDl(null2empty(UserKycTypeEnum.DRIVER_LICENSE.equals(userKycDocumentInfo.getAuthType()) ? userKycDocumentInfo.getCardId() : ""));
        stage1Request.setVoter(null2empty(UserKycTypeEnum.VOTER_ID.equals(userKycDocumentInfo.getAuthType()) ? userKycDocumentInfo.getCardId() : ""));

        stage1Request.setPassport(null2empty(UserKycTypeEnum.PASSPORT.equals(userKycDocumentInfo.getAuthType()) ? userKycDocumentInfo.getCardId() : ""));
        stage1Request.setRationC(null2empty(""));
        stage1Request.setUid(null2empty(""));
        stage1Request.setOtherId1(null2empty(""));
        stage1Request.setOtherId2(null2empty(""));

        stage1Request.setFatherName(null2empty(userInfo.getUserBase().getFatherName()));
        stage1Request.setMotherName(null2empty(userInfo.getUserBase().getMotherName()));
        stage1Request.setSpouseName(null2empty(""));
        stage1Request.setAddress1(null2empty(userInfo.getUserResident().getAddress()));
        stage1Request.setVillage1(null2empty(""));

        stage1Request.setCity1(null2empty(userInfo.getUserResident().getCity()));
        stage1Request.setState1(null2empty(userInfo.getUserResident().getProvince()));
        stage1Request.setPin1(null2empty(userInfo.getUserResident().getPinCode()));
        stage1Request.setCountry1(null2empty("india"));
        stage1Request.setAddress2(null2empty(""));

        stage1Request.setVillage2(null2empty(""));
        stage1Request.setCity2(null2empty(""));
        stage1Request.setState2(null2empty(""));
        stage1Request.setPin2(null2empty(""));
        stage1Request.setCountry2(null2empty(""));

        stage1Request.setCustomerId(null2empty(customerId));
        stage1Request.setProductCode(null2empty(productCode));
        stage1Request.setConsent(null2empty("Y"));

        String requestBody = null;
//        requestBody = "MANISHA||GOPALE||09-03-1982|||8793564813|||abc@abc.com||GAURR0857M||||||||BHASKAR|||NO.85, S.F.NO.417/2, 418/2, 419 KOTHAGONDAPALLI VILLAGE HOSUR INDUSTRIAL COMPLEX|HOSUR|HOSUR|TamilNadu|635126|india|||||||DTC0000041|BBC_CONSUMER_SCORE#85#2.0|Y|";
//        requestBody = "JEENA|JOHN|WILSON||10-04-1975|||7856397562|||abc@abc.com||VTLAN2506Q||||||||JOHN|||A-301, BALAJI APT, NEAR POLICE STATION, UTTAN ROAD|THANE|THANE|Maharashtra|401101|india|||||||DTC0000041|BBC_CONSUMER_SCORE#85#2.0|Y|";
//        requestBody = "RAM||Singh||01-01-1976|||5654812686|||abc@abc.com||||59604194982903||||||NA|||759 NAGLA VIDHI CHAND NAINAJAT|AGRA|AGRA|Uttarpradesh|282001|india|||||||DTC0000041|BBC_CONSUMER_SCORE#85#2.0|Y|";
//        requestBody = "VINITA|GOPAL|Singh||01-01-1985|||5641227822|||abc@abc.com||||65324178826583||||||GOPAL|||NAGALA KHEDIYA|AGRA|AGRA|Uttarpradesh|282001|india|||||||DTC0000041|BBC_CONSUMER_SCORE#85#2.0|Y|";

        requestBody = stage1Request.convertRequestBody();
        if (configUtil.isServerTest() && StringUtils.isNotEmpty(configUtil.getMockHighmarkBody())) {
            requestBody = configUtil.getMockHighmarkBody();
        }

        String url = configUtil.isServerTest() ? stage1Url[0] : stage1Url[1];

        String datetimestamp = DateUtil.getDate(new Date(), "dd-MM-yyyy HH:mm:ss");
//        if (configUtil.isServerTest()) {
//            datetimestamp = timeZoneTransfer(datetimestamp, "dd-MM-yyyy HH:mm:ss", "+8", "+5:30");
//        }

        String accessCodeStr = userId + "|" + customerId + "|" + productCode + "|" + password + "|" + datetimestamp;
        String accessCode = new String(new Base64().encode(accessCodeStr.getBytes()));

        Map<String, String> header = new HashMap<>();
        header.put("Content-Type", "text/plain; charset=utf-8");
        header.put("orderId", orderId);
        header.put("accessCode", accessCode);
        header.put("appID", appID);
        header.put("merchantID", merchantID);

        String result = HttpUtil.postPageBodyByHttps(url, header, requestBody);
        LOGGER.info("HighMarkStage1,请求及应答,userCode:{},orderId:{},header:{},accessCode:{},requestBody:{},response:{}",
                userCode, orderId, JSON.toJSONString(header), accessCodeStr, requestBody, result);
        if (StringUtils.isEmpty(result)) {
            throw new ApplicationException("Result is empty!");
        }
        JSONObject jsonObject = JSON.parseObject(result);

        ReportStage1Dto reportStage1Dto = new ReportStage1Dto();
        reportStage1Dto.setUserCode(userCode)
                .setOrderId(orderId)
                .setAppId(appID)
                .setMerchantId(merchantID)
                .setAccessCode(accessCode)
                .setRequest(requestBody)
                .setReportId(jsonObject.getString("reportId"))
                .setRedirectURL(jsonObject.getString("redirectURL"))
                .setStatus(jsonObject.getString("status"));
        redisClient.set(RedisKeyConsts.HIGHMARK_STAGE1_KEY, reportStage1Dto, 5 * 60 * 60, orderId);
        redisClient.set(RedisKeyConsts.HIGHMARK_STAGE1_USERCODE_KEY, reportStage1Dto, 5 * 60 * 60, userCode);

        UserHighmarkVo userHighmarkVo = new UserHighmarkVo();
        userHighmarkVo.setUserCode(userCode)
                .setOrderId(reportStage1Dto.getOrderId())
                .setReportId(reportStage1Dto.getReportId())
                .setStage(1)
                .setStatus(UserHighmarkStatusEnum.INIT.getStatus());
        userHighmarkService.addUserHighmark(userHighmarkVo);
        return orderId;
    }

    /**
     * 第二步
     * 用户验证问卷服务将提供大量3个不同的问题以验证用户身份。
     * 因此，将在对先前问题提供错误答案的情况下提供问题。如果有的话提供正确答案后，商家可以进入第3阶段。
     * 如果所有3次尝试，用户将不得不与CHM联系
     * - 在阶段2中，如果满足自动认证条件，则返回状态码– S10。这种情况会覆盖身份验证过程，则商家将进入第3阶段。
     * - 只要用户提供正确答案，就会返回状态码– S01。传递此状态代码后，商家可以进入第3个阶段获取报告。
     * - 每当用户提供错误答案时，都会返回状态码– S11。使用此状态代码，另返回一个新的问答集给商户，将重新启动第4.3节中的步骤。这将持续到三个中断。
     * - 如果用户在所有三个尝试中均替代提供正确的答案，则返回状态码– S02。这是用户授权失败方案。在这种情况下，用户将需要与CHM产品支持团队获取CIR报告
     *
     * @param orderId
     * @return 0-失败 1-成功 2-重试答题 3-次数超过限制失败
     */
    public Stage2ResultEnum stage2(String orderId, String userAns) {
        ReportStage1Dto reportStage1Dto = redisClient.get(RedisKeyConsts.HIGHMARK_STAGE1_KEY, orderId);
        if (reportStage1Dto == null) {
            throw new ApplicationException("error!");
        }
        ReportStage2Dto reportStage2DtoHistory = redisClient.get(RedisKeyConsts.HIGHMARK_STAGE2_KEY, orderId);

        String url = configUtil.isServerTest() ? stage2Url[0] : stage2Url[1];

        String accessCode = reportStage1Dto.getAccessCode();
        String merchantID = reportStage1Dto.getMerchantId();
        String reportId = reportStage1Dto.getReportId();
        String appID = reportStage1Dto.getAppId();

        Map<String, String> header = new HashMap<>();
        header.put("Content-Type", "text/plain; charset=utf-8");
        header.put("orderId", orderId);
        header.put("requestType", "Authorization");
        header.put("reportId", reportId);
        header.put("accessCode", accessCode);
        header.put("appID", appID);
        header.put("merchantID", merchantID);
        // userAns后面不需要加竖线
        String requestBody = "{orderId}|{reportId}|{accessCode}|{redirectUrl}|{paymentFlag}|{alertFlag}|{reportFlag}|{userAns}";
        requestBody = TextFormatUtil.format(requestBody, orderId, reportId, accessCode, reportStage1Dto.getRedirectURL(), "N", "N", "Y", StringUtils.isEmpty(userAns) ? "Null" : userAns);

        //发送请求
        String result = HttpUtil.postPageBodyByHttps(url, header, requestBody);
        LOGGER.info("HighMarkStage2,请求及应答,userCode:{},orderId:{},header:{},requestBody:{},response:{}",
                reportStage1Dto.getUserCode(), orderId, JSON.toJSONString(header), requestBody, result);
        if (StringUtils.isEmpty(result)) {
            return Stage2ResultEnum.FAILED;
        }
        JSONObject jsonObject = JSON.parseObject(result);
        String status = jsonObject.getString("status");

        ReportStage2Dto reportStage2Dto = new ReportStage2Dto();
        reportStage2Dto.setUserCode(reportStage1Dto.getUserCode())
                .setAccessCode(accessCode)
                .setMerchantId(merchantID)
                .setReportId(reportId)
                .setOrderId(orderId)
                .setAppId(appID)
                .setRequest(requestBody)
                .setStatusDesc(jsonObject.getString("statusDesc"))
                .setStatus(status);
        //需要验证问题
        if ("S11".equals(status)) {
            reportStage2Dto.setQuestion(jsonObject.getString("question"));
            reportStage2Dto.setOptionList(JSON.parseArray(jsonObject.getJSONArray("optionsList").toJSONString(), String.class));
            if (reportStage2DtoHistory == null) {
                reportStage2Dto.setCount(1);
            } else {
                reportStage2Dto.setCount(reportStage2DtoHistory.getCount() + 1);
            }
        }
        redisClient.set(RedisKeyConsts.HIGHMARK_STAGE2_KEY, reportStage2Dto, 5 * 60 * 60, orderId);

        UserHighmarkVo userHighmarkVo = new UserHighmarkVo();
        userHighmarkVo.setUserCode(reportStage1Dto.getUserCode())
                .setOrderId(reportStage1Dto.getOrderId())
                .setReportId(reportStage1Dto.getReportId())
                .setStage(2);
        userHighmarkService.addUserHighmark(userHighmarkVo);

        //判断是否可以进入第三步
        //S02 是一种异常情况，需要stage1重新来过
        //S11 并且错误3次以上 需要stage1重新来过
        if ("S02".equals(status) || "S11".equals(status) && reportStage2Dto.getCount() != null && reportStage2Dto.getCount() > 3) {
            userHighmarkVo.setStatus(UserHighmarkStatusEnum.FAILED.getStatus());//状态设置为失败
            userHighmarkService.addUserHighmark(userHighmarkVo);
            return Stage2ResultEnum.QUESTION_FAILED;
        }
        //S10是免校验通过 S01是答题正确后通过
        if ("S10".equals(status) || "S01".equals(status)) {
            return Stage2ResultEnum.SUCCESS;
        }
        //S11表示答题错误 需要重试
        if ("S11".equals(status)) {
            return Stage2ResultEnum.QUESTION;
        }
        //S09表示未收录该用户
        if ("S09".equals(status)) {
            return Stage2ResultEnum.NO_HIT;
        }
        return Stage2ResultEnum.FAILED;
    }

    /**
     * 第三步
     *
     * @param orderId
     * @return
     */
    public String stage3(String orderId) {
        ReportStage1Dto reportStage1Dto = redisClient.get(RedisKeyConsts.HIGHMARK_STAGE1_KEY, orderId);
        if (reportStage1Dto == null) {
            throw new ApplicationException("error!");
        }
        ReportStage2Dto reportStage2Dto = redisClient.get(RedisKeyConsts.HIGHMARK_STAGE2_KEY, orderId);
        if (reportStage2Dto == null) {
            throw new ApplicationException("error!");
        }

        String url = configUtil.isServerTest() ? stage3Url[0] : stage3Url[1];

        String accessCode = reportStage1Dto.getAccessCode();
        String merchantID = reportStage1Dto.getMerchantId();
        String reportId = reportStage1Dto.getReportId();
        String appID = reportStage1Dto.getAppId();

        Map<String, String> header = new HashMap<>();
        header.put("Content-Type", "text/plain; charset=utf-8");
        header.put("accessCode", accessCode);
        header.put("orderId", orderId);
        header.put("reportId", reportId);
        header.put("merchantID", merchantID);
        header.put("appID", appID);

        String requestBody = "{orderId}|{reportId}|{accessCode}|{redirectUrl}|{paymentFlag}|{alertFlag}|{reportFlag}|";
        requestBody = TextFormatUtil.format(requestBody, orderId, reportId, accessCode, reportStage1Dto.getRedirectURL(), "N", "N", "Y");

        //发送请求
        String result = HttpUtil.postPageBodyByHttps(url, header, requestBody);
        LOGGER.info("HighMarkStage3,请求及应答,userCode:{},orderId:{},header:{},requestBody:{},response:{}",
                reportStage1Dto.getUserCode(), orderId, JSON.toJSONString(header), requestBody, result);
        if (StringUtils.isEmpty(result)) {
            return null;
        }
        String reportXmlUrl = "";
        try {
            String ossFilePath = "highmark/" + DateUtil.getDate(new Date(), "yyyyMMdd") + "/" + orderId + ".txt";
            InputStream inputStream = new ByteArrayInputStream(result.getBytes());
            ossService.uploadFile(configUtil.getBucketName(), inputStream, inputStream.available(), ossFilePath);
            reportXmlUrl = configUtil.getQsyqBaseUrl() + ossFilePath;
        } catch (Exception e) {
            LOGGER.error("上传报告到OSS失败,orderId:{},userCode:{},result:{}", reportStage1Dto.getOrderId(), reportStage1Dto.getUserCode(), result);
        }

//        ReportStage3Dto reportStage3Dto = new ReportStage3Dto();
//        reportStage3Dto.setUserCode(reportStage1Dto.getUserCode())
//                .setAccessCode(accessCode)
//                .setMerchantId(merchantID)
//                .setReportId(reportId)
//                .setOrderId(orderId)
//                .setAppId(appID)
//                .setReportId(reportId)
//                .setReportXml(result);
//        redisClient.set(RedisKeyConsts.HIGHMARK_STAGE3_KEY, reportStage3Dto, 5 * 60 * 60, orderId);

        UserHighmarkVo userHighmarkVo = new UserHighmarkVo();
        userHighmarkVo.setUserCode(reportStage1Dto.getUserCode())
                .setOrderId(reportStage1Dto.getOrderId())
                .setReportId(reportStage1Dto.getReportId())
                .setStage(3)
                .setStatus(UserHighmarkStatusEnum.SUCCESS.getStatus())//状态设置为成功
                .setReportData(reportXmlUrl);
        userHighmarkService.addUserHighmark(userHighmarkVo);
        return result;
    }


    /**
     * 时区转换
     *
     * @param time           时间字符串
     * @param pattern        格式 "yyyy-MM-dd HH:mm"
     * @param nowTimeZone    eg:+8，0，+9，-1 等等
     * @param targetTimeZone 同nowTimeZone
     * @return
     */
    public String timeZoneTransfer(String time, String pattern, String nowTimeZone, String targetTimeZone) {
        if (StringUtils.isEmpty(time)) {
            return "";
        }
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT" + nowTimeZone));
        Date date;
        try {
            date = simpleDateFormat.parse(time);
        } catch (Exception e) {
            return "";
        }
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("GMT" + targetTimeZone));
        return simpleDateFormat.format(date);
    }

    private String null2empty(String str) {
        if (str == null) {
            return "";
        }
        return str;
    }
}
